package org.sfx.control

import javafx.beans.InvalidationListener
import javafx.beans.Observable
import javafx.event.EventHandler
import javafx.scene.Group
import javafx.scene.Node
import javafx.scene.control.Label
import javafx.scene.control.Skin
import javafx.scene.input.MouseEvent
import javafx.scene.paint.Color
import javafx.scene.paint.CycleMethod
import javafx.scene.paint.LinearGradient
import javafx.scene.paint.Stop
import javafx.scene.shape.HLineTo
import javafx.scene.shape.MoveTo
import javafx.scene.shape.Path
import javafx.scene.shape.QuadCurveTo
import javafx.scene.shape.VLineTo
import javafx.event.ActionEvent
import java.util.Arrays

object ArrowButtonSkin {
  val ARROW_TIP_WIDTH = 5.0
  val RIGHT = 1
}

class ArrowButtonSkin(val control: ArrowButton) extends Skin[ArrowButton] {
  import ArrowButtonSkin._
  import org.sfx.util.Conversions._
  
  var text = ""
  val rootNode = new Group()
  val lbl = new Label(text + "MOO")
  var direction = RIGHT
  var clientEH: EventHandler[MouseEvent] = null

  rootNode.setOnMouseClicked(new EventHandler[MouseEvent]() {
    def handle(event: MouseEvent): Unit = {
      // Pass along to client if an event handler was provided
      if (clientEH != null)
        clientEH.handle(event)
    }
  })

  lbl.setTranslateX(2)
  lbl.setTranslateY(2)
  
  // Create arrow button line path elements
  val path = new Path()
  val startPoint = new MoveTo()
  val topLine = new HLineTo()
   
  val quadCurveTop = new QuadCurveTo()
  val quadCurveBott = new QuadCurveTo()
   
  val bottomLine = new HLineTo()
  val endLine = new VLineTo()
   
  path.getElements().add(startPoint)
  path.getElements().add(topLine)
  path.getElements().add(quadCurveTop)
  path.getElements().add(quadCurveBott)
  path.getElements().add(bottomLine)
  path.getElements().add(endLine)
    
  // Create and set a gradient for the inside of the button
  val stops = Arrays.asList(
      new Stop(0.0, Color.LIGHTGREY),
      new Stop(1.0, Color.SLATEGREY))
  val lg = new LinearGradient(0.0, 0.0, 0.0, 1.0, true, CycleMethod.NO_CYCLE, stops)
  path.setFill(lg)
      
  rootNode.getChildren().setAll(path, lbl)
  
  val listener = { _: Observable =>
    val labelWidth = lbl.getLayoutBounds().getWidth()
    val labelHeight = lbl.getHeight()
    val height = labelHeight 
    var x = 0.0
    var y = 0.0
    var controlX = 0.0
    var controlY = 0.0
    startPoint.setX(x)
    startPoint.setY(y)
    x += labelWidth
    topLine.setX(x)
    
    // Top curve
    controlX = x + ARROW_TIP_WIDTH
    controlY = y
    x += 10
    y = height / 2
         
    quadCurveTop.setX(x)
    quadCurveTop.setY(y)
    quadCurveTop.setControlX(controlX)
    quadCurveTop.setControlY(controlY)
         
    // Bottom curve
    controlX = x - ARROW_TIP_WIDTH
    x -= 10
    y = height
    controlY = y

    quadCurveBott.setX(x)
    quadCurveBott.setY(y)
    quadCurveBott.setControlX(controlX)
    quadCurveBott.setControlY(controlY)
    x -= labelWidth
    bottomLine.setX(x)
    endLine.setY(0)
  }

  lbl.widthProperty().addListener(listener)
  lbl.heightProperty().addListener(listener)

  def getControl(): ArrowButton = {
    return control
  }

  def getNode(): Node = {
    return rootNode
  }

  def dispose(): Unit = {
  }

  //////////////////////////////////////////////////////////////

  def setText(text: String): Unit = {
    this.text = text
    lbl.setText(text)
  }

  def setOnMouseClicked2(eh: EventHandler[MouseEvent]): Unit = {
    clientEH = eh
  }

  def setDirection(direction: Integer): Unit = {
    this.direction = direction
  }

  override def getSkinnable(): ArrowButton = {
    return control
  }
}
